/*
 * Copyright (c) 2010 Curtis Boyden.  All rights reserved. 
 * This software was developed by Curtis Boyden and is provided under the terms 
 * of the GNU Lesser General Public License, Version 2.1. You may not use 
 * this file except in compliance with the license. If you need a copy of the license, 
 * please go to http://www.gnu.org/licenses/lgpl-2.1.txt. The Original Code is ejMud
 * (Ewerp Java MUD).  The Initial Developer is Curtis Boyden.
 *
 * Software distributed under the GNU Lesser Public License is distributed on an "AS IS" 
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to 
 * the license for the specific language governing your rights and limitations.
 */

package com.ewerp.mud.core.plugin;

import java.util.ArrayList;
import java.util.List;

import com.ewerp.mud.commands.engine.EwerpCommandEngine;
import com.ewerp.mud.core.lifecycle.ILifecycleListener;
import com.ewerp.mud.core.persistence.EwerpHibernatePersistence;
import com.ewerp.mud.core.session.EwerpSessionManager;

public class EwerpPluginManager implements IPluginManager, ILifecycleListener {
    private static final EwerpPluginManager instance = new EwerpPluginManager();
    private static final String defaultNamespace = "EWERP_DEFAULT";
    
    private List<PluginReference> pluginList = new ArrayList<PluginReference>();
    
    protected static class PluginReference {
        private String namespace;
        private IPlugin plugin;
        
        public PluginReference(String namespace, IPlugin plugin) {
            this.namespace = namespace;
            this.plugin = plugin;
        }
        
        public void setNamespace(String namespace) {
            this.namespace = namespace;
        }
        
        public String getNamespace() {
            return namespace;
        }
        
        public void setPlugin(IPlugin plugin) {
            this.plugin = plugin;
        }
        
        public IPlugin getPlugin() {
            return plugin;
        }
        
        public boolean supportsClass(Class<?> clazz) {
            if(plugin.getInterfaces() == null) {
                return false;
            }
            // This method would let us get rid of the getInterfaces() method
            // however we would lose control over what a plugin exposes
//            if(plugin.getClass().isAssignableFrom(clazz.getClass())) {
//                return true;
//            }
            if(plugin.getInterfaces().contains(clazz)) {
                return true;
            }
            
            return false;
        }
    }

    public static final EwerpPluginManager getInstance() {
        return instance;
    }

    @Override
    public IPlugin getPlugin(Class<?> clazz) throws IllegalArgumentException {
        return getPlugin(defaultNamespace, clazz);
    }

    @Override
    public void addPlugin(IPlugin plugin) throws IllegalArgumentException {
        addPlugin(defaultNamespace, plugin);
    }

    @Override
    public IPlugin getPlugin(String namespace, Class<?> clazz) throws IllegalArgumentException {
        if(clazz == null) {
            throw new IllegalArgumentException("parameter 'clazz' must not be null");
        }
        IPlugin result = null;
        
        String useNamespace = namespace;
        if(namespace == null) {
            useNamespace = defaultNamespace;
        }
        
        for(PluginReference pluginReference : pluginList) {
            if((pluginReference.getNamespace() == null || pluginReference.getNamespace().equals(useNamespace)) 
                    && pluginReference.supportsClass(clazz)) {
                result = pluginReference.getPlugin();
                break;
            }
        }
        
        return result;
    }

    @Override
    public void addPlugin(String namespace, IPlugin plugin) throws IllegalArgumentException {
        if(plugin == null) {
            throw new IllegalArgumentException("parameter 'plugin' must not be null");
        }
        String useNamespace = namespace;
        if(namespace == null) {
            useNamespace = defaultNamespace;
        }
        pluginList.add(new PluginReference(useNamespace, plugin));
        plugin.registerPluginManager(this);
    }

    @Override
    public void init() {
        // Load plugins
        addPlugin(EwerpHibernatePersistence.getInstance());
        addPlugin(EwerpCommandEngine.getInstance());
        addPlugin(EwerpSessionManager.getInstance());
        
        for(PluginReference pluginReference : pluginList) {
            if(pluginReference.getPlugin() instanceof ILifecycleListener) {
                ((ILifecycleListener)pluginReference.getPlugin()).init();
            }
        }
    }

    @Override
    public void start() {
        for(PluginReference pluginReference : pluginList) {
            if(pluginReference.getPlugin() instanceof ILifecycleListener) {
                ((ILifecycleListener)pluginReference.getPlugin()).start();
            }
        }
    }

    @Override
    public void stop() {
        for(PluginReference pluginReference : pluginList) {
            if(pluginReference.getPlugin() instanceof ILifecycleListener) {
                ((ILifecycleListener)pluginReference.getPlugin()).stop();
            }
        }
    }
}